import Cesium, { Cartesian3, Primitive, Rectangle } from '../Ces/Cesium'
import WeDisplay from './WeDisplay'
import WeDisplayParameter from "./WeDisplayParameter"
import { fragmentMain } from './WeVoxelPrimitiveShaders'

class WeVoxelPrimitive {
  private _primitive: any
  private fragmentMain: string
  private display: WeDisplay
  private jitter: boolean
  private debugDraw: boolean
  private depthTest: boolean
  private show: boolean
  private rectangle: Rectangle
  private minBounds: Cartesian3
  private maxBounds: Cartesian3
  private dimensions: Cartesian3
  private names
  private types
  private componentTypes
  private maximumTileCount
  private shape
  constructor(options) {
    this.fragmentMain = options.fragmentMain
    this.display = options.display
    const rectangle = options.rectangle
    const shape = Cesium.VoxelShapeType.ELLIPSOID
    this.jitter = options.jitter?? true
    this.depthTest = options.depthTest?? true
    this.debugDraw = options.debugDraw?? false
    const minBounds = Cesium.Cartesian3.clone(
      Cesium.VoxelShapeType.getMinBounds(shape),
    )

    const maxBounds = Cesium.Cartesian3.clone(
      Cesium.VoxelShapeType.getMaxBounds(shape),
    )
    this.rectangle = options.rectangle
    minBounds.x = rectangle.west
    minBounds.y = rectangle.south
    minBounds.z = 0.0

    maxBounds.x = rectangle.east
    maxBounds.y = rectangle.north
    maxBounds.z = options.dataProvider.externalData.size.depth

    this.minBounds = minBounds
    this.maxBounds = maxBounds

    this.dimensions = new Cesium.Cartesian3(1, 1, 1)
    this.names = ['value']
    this.types = [Cesium.MetadataType.SCALAR]
    this.componentTypes = [Cesium.MetadataComponentType.UNSIGNED_BYTE]
    this.maximumTileCount = 1
    this.shape = shape

    this.rebuild()
    this.show = true
  }


  rebuild() {
    const modelMatrix = Cesium.Matrix4.fromScale(
      Cesium.Cartesian3.fromElements(
        Cesium.Ellipsoid.WGS84.maximumRadius,
        Cesium.Ellipsoid.WGS84.maximumRadius,
        Cesium.Ellipsoid.WGS84.minimumRadius,
      ),
    )

    const display = this.display

    const baseFragmentSource = display.getFragmentShaderSource(true, true, true)

    const rectangle = this.rectangle

    const customShader = new Cesium.CustomShader({
      uniforms: {
        u_localExtent: {
          type: Cesium.UniformType.VEC4,
          value: new Cesium.Cartesian4(rectangle.west, rectangle.south, rectangle.east, rectangle.north),
        }
      },
      fragmentShaderText: `
        ${WeDisplayParameter.getSource(true)}
        ${baseFragmentSource}
        ${this.fragmentMain || fragmentMain}
        `,
      })

    display.setupUniformMap(customShader.uniformMap)
    WeDisplayParameter.setupUniformMap(customShader.uniformMap)

    this._primitive = new Cesium.VoxelPrimitive({
      customShader,
      modelMatrix,
      provider: this,
    })

    this._primitive.depthTest = this.depthTest
    this._primitive.jitter = this.jitter
    this._primitive.debugDraw = this.debugDraw
    this._primitive.levelBlendFactor = 0.0
    this._primitive.disableUpdate = false
  }

  requestData(
    options,
  ) {
    const tileLevel = options.tileLevel

    if (tileLevel >= 1) {
      return undefined
    }
    const content = Cesium.VoxelContent.fromMetadataArray([new Uint8Array(1)])

    return Promise.resolve(content)
  }

  isDestroyed() {
    return false
  }

  destroy() {
    this._primitive = this._primitive && this._primitive.destroy()
    return Cesium.destroyObject(this)
  }

  update(frameState) {
    if (!this.show) return
    if (frameState.passes.render && this._primitive) {
      this._primitive.stepSize = 1 / WeDisplayParameter.Volume.numIteration
      const verticalExaggerationCopy = frameState.verticalExaggeration + 0.0
      frameState.verticalExaggeration = WeDisplayParameter.scaleZ
      this._primitive.update(frameState)
      frameState.verticalExaggeration = verticalExaggerationCopy
    }
  }
}

export default WeVoxelPrimitive
